package com.share.config.jdkproxy;

import com.alibaba.fastjson.JSON;
import com.share.common.utils.AnnotationUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Map;


/**
 * 代理模式通过接口生成对象
 */
@Slf4j
@Component
public class FeignClientFallbackConfig {
    static Map<Class, Annotation> classWithAnnotation;

    @Autowired
    private AutowireCapableBeanFactory beanFactory;

    @Autowired
    private DefaultListableBeanFactory defaultListableBeanFactory;

    FeignClientFallbackConfig() {
        //1.提取注解类
        String pkg = this.getClass().getPackage().getName();//定位到根节点
        this.classWithAnnotation = AnnotationUtil.findClassWithAnnotation(pkg, ComponentScans.class);
        log.info("检测到的feign={}", JSON.toJSONString(this.classWithAnnotation.keySet()));
    }

    @PostConstruct
    public void init() {
        if (CollectionUtils.isEmpty(this.classWithAnnotation)) {
            throw new RuntimeException("未检测到feign调用的类与接口");
        }

        //1.为标记的类生成代理对象
        for (Class clazz : this.classWithAnnotation.keySet()) {
            ComponentScans annotation = (ComponentScans) this.classWithAnnotation.get(clazz);

            //2.回调未配置
            Class fallbackClazz = annotation.getClass();
            if (fallbackClazz == null) {
                continue;
            }

            //2.校验配置是否正确
            boolean isParent = false;
            Type[] genericInterfaces = fallbackClazz.getGenericInterfaces();
            if (!ArrayUtils.isEmpty(genericInterfaces)) {
                for (Type type : genericInterfaces) {
                    if (clazz.equals((Class) type)) {
                        isParent = true;
                        break;
                    }
                }
            }

            if (!isParent) {
                throw new RuntimeException(String.format("Feign注解属性fallback=%s,没有继承Feign注解类clazz=%s", fallbackClazz, clazz));
            }
            log.info("Feign注解类clazz={},Feign注解属性fallback={}", clazz, fallbackClazz);

            //生产代理对象
            Object proxy = new FeignClientFallbackJDKProxy().getProxy(fallbackClazz);
            defaultListableBeanFactory.registerSingleton(fallbackClazz.getName(), proxy);
            beanFactory.autowireBean(proxy);
        }
    }
}
